#!/usr/bin/python
'''The Account Manager handles the UI for creating, editing, and deleting accounts. It shows
the status of each account (connected/disconnected).
When an account is connected, the account_manager creates a new service UI. When that service UI
is closed, the status is reflected on the account icon.

Account properties are handled by the account_props class.
'''
ident = '$Id: account_manager.py 146 2006-08-23 01:42:44Z trevor $'
import wx, sys
from wx.lib.mixins.listctrl 	import ColumnSorterMixin
import common
import icon_manager
import images
import webbrowser
import rex
import account_ui
import about
import tracer
import time
import os
from xml.dom	import minidom
import wx.lib.hyperlink as hl

# Button IDs
ID_CREATE_ACCOUNT = 101
ID_EDIT_ACCOUNT   = 102
ID_DELETE_ACCOUNT = 103
ID_CONNECT_ACCOUNT= 104
ID_FRAME_TIMER    = 120
ID_HIDE_TIMER	  = 121

IDM_CREATE		= 201
IDM_CONNECT		= 202
IDM_EDIT		= 203
IDM_DELETE		= 204
IDM_EXIT		= 205
IDM_ABOUT		= 206
IDM_SUPPORT		= 208
IDM_TRACE		= 209
IDM_FONTS		= 210
IDM_IMPORT		= 211

#################################
class starterWindow(wx.Panel):
	def __init__(self, parent, id=-1, size=wx.DefaultSize, bgcolor=None):
		wx.Panel.__init__( self, parent )
		self.parent = parent
		self.grid = wx.FlexGridSizer( 7, 2, 20, 20 )
		self.username  = wx.TextCtrl(self, -1, '')
		self.password = wx.TextCtrl(self, -1, '',style=wx.TE_PASSWORD)
		self.button = wx.Button(self, IDM_IMPORT, 'Import')
		self.button.Bind(wx.EVT_BUTTON, self.OnButton)
		self.thx = wx.Button(self, IDM_IMPORT, 'No thanks')
		self.thx.Bind(wx.EVT_BUTTON, self.OnThx)
		self.devlink = hl.HyperLinkCtrl(self, wx.ID_ANY, "Get A New Etelos Developer Account", URL="http://www.etelos.com/devaccount/")
		Msg1 = """
Welcome to Etelos OpenDev!

If you have an Etelos Support or Etelos Store username
and password, please login to import your server accounts.

		"""
		Msg2 = """
Or you can click the link below to 
		"""
		inputs = [ 
			( (0,0) ),
			(wx.StaticText( self, -1, Msg1 , style=wx.ALIGN_LEFT ), 0, wx.EXPAND),
			( wx.StaticText( self, -1, "Username", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
			( self.username, 1, wx.EXPAND | wx.GROW ),
			( wx.StaticText( self, -1, "Password", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
			( self.password, 1, wx.EXPAND | wx.GROW ),
			((0,0)),
			( self.button,1,wx.EXPAND),
			((0,0)),
			( wx.StaticText( self, -1, Msg2 , style=wx.ALIGN_LEFT ), 0, wx.EXPAND ),
			((0,0)),
			(self.devlink,1,wx.EXPAND),
			((0,0)),
			( self.thx,1,wx.EXPAND) ]
		self.grid.AddMany( inputs )
		self.grid.AddGrowableCol( 1 )
		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( self.grid, 1, wx.EXPAND|wx.NORTH|wx.SOUTH|wx.EAST|wx.WEST,50 )
		self.SetSizer(self.sizer)

	def OnButton(self,event):
		username = self.username.GetValue()
		password = self.password.GetValue()
		common.dprint( "Got username: %s password: %s " % (username,password))
		busy = wx.BusyInfo("One moment please, downloading account information...")
		wx.Yield()
		time.sleep(1)
		vars = [( u'username', username ),
				( u'password', password ),
				( u'rtalk', u'71' ),]
		result = False
		doc = ''
		try:
			form= common.http_post_form( 'www.etelos.com', '/developer/accounts.esp', vars )
			common.dprint("Sending request");
			doc	= form.submit()
			common.dprint("Got result: %s" % doc);
			doc = doc.strip()
			if len( doc ) < 10:
				common.dprint( "Download failed: ", doc )
			else:
				result = True
		except:
			common.show_error("Failed to download accounts information")
		del busy
		# got accounts
		xmlstring = common.uni2str( doc )
		pdom 	= minidom.parseString( xmlstring )
		for anode in pdom.getElementsByTagName("account"):
			account_name = anode.getAttribute('name')
			account_server = anode.getAttribute('server')
			account_username = anode.getAttribute('username')
			account_password = anode.getAttribute('password')
			account_projectdir = os.path.join(os.path.expanduser('~'),'opendev',account_name)
			account = rex.accounts.create_account( account_name, account_server, account_username, account_password )
		# We are done, lets close up
		self.parent.GetParent().refreshAccountsList()
		self.OnThx()
		
	def OnThx(self,event=None):
		self.parent.GetParent().OnImport(None)
	
	def OnNewAccount(self,event=None):
		webbrowser.open("http://support.etelos.com")
#################################
class account_manager( wx.Frame ):
	'''The Account Manager UI Frame'''
	def __init__( self, parent, id, title ):
		window_pos	= ( common.account_manager_x, common.account_manager_y )
		window_size	= ( common.account_manager_w, common.account_manager_h )
		wx.Frame.__init__( self, parent, id, title, pos=window_pos, size=window_size,
			style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE )
		common.metalic(self)
		self.inStarterMode = False
		self.currentItem= None
		self.services 	= {}
		self.sort_asc	= True
		self.create_menu_items()
		# Connect a timer to this frame
		self.timer = wx.Timer( self, ID_FRAME_TIMER )
		self.hide_me_timer = wx.Timer( self, ID_HIDE_TIMER )
		self.Bind( wx.EVT_TIMER, self.OnTimer )
		# Create an image list
		self.il = wx.ImageList(16, 16)
		# Load our images
		self.disconnected_icon 	= self.il.Add( images.getDisconnectedBitmap() )
		self.connecting_icon 	= self.il.Add( images.getConnectingBitmap() )
		self.connected_icon 	= self.il.Add( images.getConnectedBitmap() )
		self.failed_icon 		= self.il.Add( images.getFailedBitmap() )		
		self.splitter = wx.SplitterWindow( self, -1 )
		# Create the list control and set it's image list
		tID = wx.NewId()
		self.list = wx.ListCtrl(self.splitter, tID, style=wx.LC_REPORT|wx.LC_SINGLE_SEL )#|wx.LC_VRULES|wx.LC_HRULES)
		self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
		# Create the column headers
		info = wx.ListItem()
		info.m_mask = wx.LIST_MASK_TEXT # | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT
		info.m_image = -1
		info.m_text = "Account"
		self.list.InsertColumnInfo(0, info)
		info.m_text = "Status"
		self.list.InsertColumnInfo(1, info)
		info.m_text = "Server"
		self.list.InsertColumnInfo(2, info)
		# Set the events
		self.Bind( wx.EVT_LIST_ITEM_ACTIVATED, self.OnActivateAccount, id=tID )
		self.Bind( wx.EVT_LIST_COL_CLICK, self.OnColClick, id=tID )
		self.Bind( wx.EVT_CLOSE, self.OnClose )
		self.list.Bind( wx.EVT_RIGHT_DOWN, self.OnAccountRightClick )
		# Create a status bar
		self.CreateStatusBar()
		# Now sizeup the whole set
		# the html window
		self.starter = starterWindow(self.splitter)
		self.splitter.SplitHorizontally( self.list, self.starter )
		self.splitter.Unsplit(self.starter)
		self.list.Show()
		self.list.Refresh()
		self.starter.Show(False)
		#self.starter.Refresh()
		self.splitter.Show()
		self.splitter.Refresh()
		# Set the frame icon
		icon = icon_manager.get_icon( "ESM" )
		self.SetIcon( icon )
		self.SetStatusText( "Ready" )
		# Sort the accounts by name
		self.clicked_column = 0
		self.list.SortItems( self.OnSort )
				
	def create_menu_items( self ):
		# Create the menu bar
		menubar = wx.MenuBar()
		self.menubar = menubar
		# The accounts menu
		menu = wx.Menu()
		menu.Append( IDM_CONNECT,"Co&nnect"," Connect to the selected service account" )
		menu.AppendSeparator()
		self.create_mi = wx.MenuItem( menu, IDM_CREATE, "&Create", " Create a new service account" )
		menu.AppendItem( self.create_mi )
		self.import_mi = wx.MenuItem( menu, IDM_IMPORT, "&Import", " Import accounts from your Etelos Developer account" )
		menu.AppendItem( self.import_mi )
		menu.Append( IDM_EDIT,   "&Edit",   " Edit the selected service account" )
		self.delete_mi = wx.MenuItem( menu, IDM_DELETE, "&Delete", " Delete the selected service account" )
		menu.AppendItem( self.delete_mi )
		menu.AppendSeparator()
		menu.Append( IDM_EXIT, "E&xit", " Exit the Etelos Services Manager" )
		self.Bind( wx.EVT_MENU, self.OnCreateAccount, id=IDM_CREATE )
		self.Bind( wx.EVT_MENU, self.OnImport, id=IDM_IMPORT )
		self.Bind( wx.EVT_MENU, self.OnActivateAccount, id=IDM_CONNECT )
		self.Bind( wx.EVT_MENU, self.OnEditAccount, id=IDM_EDIT	)
		self.Bind( wx.EVT_MENU, self.OnDeleteAccount, id=IDM_DELETE )
		self.Bind( wx.EVT_MENU, self.OnClose, id=IDM_EXIT )
		menubar.Append( menu, "&Account" )
		self.accounts_menu = menu

		# The frm menu
		menu = wx.Menu()
		menu.Append( IDM_SUPPORT, 	 "&Support"," Connect to Etelos support services" )
		menu.Append( IDM_TRACE, 	 "&Open Tracer", " Open the EDE Trace Utility" )
		menu.Append( IDM_FONTS, 	 "Set Editor &Font", " Set the default editor font" )
		menu.AppendSeparator()
		menu.Append( IDM_ABOUT, 	 "&About EDE", " About EDE" )
		self.Bind( wx.EVT_MENU, self.OnAbout,		id=IDM_ABOUT )
		self.Bind( wx.EVT_MENU, self.OnTrace,		id=IDM_TRACE )
		self.Bind( wx.EVT_MENU, self.OnSelectFont,	id=IDM_FONTS )
		self.Bind( wx.EVT_MENU, self.OnSupport,		id=IDM_SUPPORT )
		menubar.Append( menu, "&Help" )
		# All done
		self.SetMenuBar( menubar )

	def OnImport(self,event=None):
		if not self.inStarterMode:
			self.inStarterMode = True
			self.splitter.SplitHorizontally(self.starter,self.list,300)
			self.splitter.Unsplit(self.list)
			self.list.Show(False)
			self.starter.Show(True)
		else:
			self.inStarterMode = False
			self.splitter.SplitHorizontally(self.list,self.starter,300)
			self.splitter.Unsplit(self.starter)
			self.starter.Show(False)
			self.list.Show(True)

	def OnSelectFont( self, event ):
		data = wx.FontData()
		data.EnableEffects( True )
		font = wx.Font( int( common.default_font_size ), wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, common.default_font_family )
		data.SetInitialFont( font )
		dlg = wx.FontDialog(self, data)
		if dlg.ShowModal() == wx.ID_OK:
			data = dlg.GetFontData()
			font = data.GetChosenFont()
			try:
				common.default_font_family = font.GetFaceName()
				common.default_font_size = int( font.GetPointSize() )
			except:
				pass
			rex.accounts.save_conf_file()
		dlg.Destroy()

	def OnClose( self, event ):
		for name,account in rex.accounts.accounts.items():
			if account.connected and account.window:
				common.dprint("Disconnecting this account")
				account.window.OnDisconnect( None )
		self.Destroy()

	def OnAbout( self, event ):
		dlg = about.AboutDialog()
		dlg.ShowModal()
		dlg.Destroy()
		del dlg

	def OnSupport( self, event ):
		webbrowser.open("http://support.etelos.com")

	def OnTrace( self, event ):
		try:
			if common.tracer is None:
				common.tracer	= tracer.tracer( self )
				common.tracer.Show()
			else:
				common.tracer.Raise()
		except:
			common.show_error("Failed to open the tracer")

	def Show( self, show_it=True ):
		# Load the accounts
		rex.accounts.load_accounts()
		# Add the accounts
		self.reload_accounts()
		self.resize_columns()
		self.list.SortItems( self.OnSort )
		wx.Frame.Show( self, show_it )
		if common.firstrun:
			self.OnImport(None)
			common.firstrun = False

	def get_icon_id_from_kind( self, kind ):
		ticon = 0
		if kind == "Newsletter":
			ticon = self.newsletter_icon
		elif kind == "Web":
			ticon = self.web_icon
		elif kind == "Email":
			ticon = self.email_icon
		elif kind == "Survey":
			ticon = self.survey_icon
		elif kind == "Referral":
			ticon = self.referral_icon
		return ticon
	def refreshAccountsList(self,event=None):
		self.reload_accounts()
		self.resize_columns()
	def reload_accounts( self ):
		'''Used internally to reload the accounts list'''
		self.list.DeleteAllItems()
		for account_id in rex.accounts.accounts:
			account = rex.accounts.accounts[ account_id ]
			# For now, hardcode Web
			index = self.list.InsertImageStringItem( sys.maxint, account.name, self.disconnected_icon )
			self.list.SetStringItem( index, 1, "Ready" )
			self.list.SetStringItem( index, 2, account.server )
			self.list.SetItemData( index, account_id )
		self.currentItem = None

	def resize_columns( self ):
		'''Used internally to recalculate the column sizes'''
		# Set the column header sizes
		self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
		self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
		self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)

	def OnAccountRightClick( self, event ):
		try:
			self.x = event.GetX()
			self.y = event.GetY()
			item, flags = self.list.HitTest((self.x, self.y))
			if flags & wx.LIST_HITTEST_ONITEM:
				self.list.Select(item)
		except:
			pass
		self.PopupMenu( self.accounts_menu, wx.Point( event.m_x, event.m_y + 10) )

	def OnItemActivated(self, event):
		'''Sets the internal currentItem variable to the currently selected account list item'''
		self.currentItem = event.m_itemIndex

	def OnCreateAccount( self, event ):
		'''Handles requests to create a new account'''
		if self.currentItem is None:
			item = None
		else:
			item = self.list.GetItem( self.currentItem )
		# Create an account properties dialog
		dlg = account_props( self, None )
		common.metalic( dlg )
		res = dlg.ShowModal()
		if res != wx.ID_OK:
			dlg.Destroy()
			dlg = None
			return
		# We are in business
		name, server, username, password = (
				dlg.name_control.GetValue(),
				dlg.server_control.GetValue(),
				dlg.username_control.GetValue(),
				dlg.password_control.GetValue() )
		account = rex.accounts.create_account( name, server, username, password )
		if account is None:
			return
		index = self.list.InsertImageStringItem( sys.maxint, account.name, self.disconnected_icon )
		self.list.SetStringItem( index, 1, "Ready" )
		self.list.SetStringItem( index, 2, account.server )
		self.list.SetItemData( index, account.id )
		self.resize_columns()

	def OnEditAccount( self, event ):
		'''Handles requests to edit the selected account'''
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		self.currentItem = sel[0]
		item = self.list.GetItem( self.currentItem )
		ai = item.GetData()
		account = rex.accounts.accounts[ ai ]
		oldname = account.name
		if account.connected:
			dlg = wx.MessageDialog( self, "This account is currently connected", "Edit Account", wx.OK )
			icon = icon_manager.get_icon( "ESM" )
			dlg.SetIcon( icon )
			dlg.ShowModal()
			dlg.Destroy()
			dlg = None
			return
		# Create an account properties dialog
		dlg = account_props( self, account )
		common.metalic( dlg )
		res = dlg.ShowModal()
		if res != wx.ID_OK:
			dlg.Destroy()
			dlg = None
			return
		# We are in business
		#full_url = "%s/soap/%s.esp" % ( url, type.lower() )
		account.name, \
		account.server, \
		account.username, \
		account.password  = (
		dlg.name_control.GetValue(),
		dlg.server_control.GetValue(),
		dlg.username_control.GetValue(),
		dlg.password_control.GetValue() )
		if( oldname != account.name ):
			account.save( oldname )
		else:
			account.save()
		#~ ticon = self.get_icon_id_from_kind( account.module )
		item.SetText( account.name )
		#~ item.SetImage( ticon )
		#~ self.list.SetStringItem( self.currentItem , 2, account.module )
		self.list.SetStringItem( self.currentItem , 2, account.server )
		self.list.SetItem( item )
		self.resize_columns()

	def OnDeleteAccount( self, event ):
		'''Handles requests to delete the selected account'''
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		self.currentItem = sel[0]
		item = self.list.GetItem( self.currentItem )
		ai = item.GetData()
		account = rex.accounts.accounts[ ai ]
		if account.connected:
			dlg = wx.MessageDialog( self, "This account is currently connected", "Delete Account",
									wx.OK )
			icon = icon_manager.get_icon( "ESM" )
			dlg.SetIcon( icon )
			dlg.ShowModal()
			dlg.Destroy()
			dlg = None
			return
		# Confirm
		dlg = wx.MessageDialog( self, "Are you sure you want to delete this account?\n\n    %s" % \
							   account.name, "Confirm Delete", wx.YES_NO )
		icon = icon_manager.get_icon( "ESM" )
		dlg.SetIcon( icon )
		if dlg.ShowModal() != wx.ID_YES:
			dlg.Destroy()
			dlg = None
			return
		rex.accounts.delete_account( account.id )
		self.list.DeleteItem( item.GetId() )
		self.resize_columns()

	def OnActivateAccount( self, event ):
		'''Handles requests to connect an account'''
		# Do we have a selected account?
		sel = common.get_selected_in_list( self.list )
		if len( sel ) < 1: return
		self.currentItem = sel[0]
		if self.currentItem is None: return
		# Get the item
		item = self.list.GetItem( self.currentItem )
		# Get the account index and attempt a connection
		aid  = item.GetData()
		account = rex.accounts.accounts[ aid ]
		if account.window is not None:
			account.window.Raise()
			return
		self.SetStatusText( "Connecting ..." )
		common.set_busy_info( "Connecting to %s..." % account.server )
		self.list.SetStringItem( self.currentItem, 0, account.name, self.connecting_icon )
		self.list.SetStringItem( self.currentItem, 1, "Trying..." )
		self.resize_columns()
		wx.Yield()
		cur = wx.BusyCursor()
		wx.Yield()
		try:
			account.connect()
		except:
			common.show_error('')
			print "Failed to connect"
		del cur
		common.clear_busy_info()
		# Are we connected?
		if not account.connected:
			self.list.SetStringItem( self.currentItem, 0, account.name, self.failed_icon )
			self.list.SetStringItem( self.currentItem, 1, "Failed" )
			self.resize_columns()
			wx.Yield()
			self.SetStatusText( "Failed to connect" )
			return
		else:
			self.list.SetStringItem( self.currentItem, 0, account.name, self.connected_icon )
			self.list.SetStringItem( self.currentItem, 1, "Connected" )
			self.resize_columns()
			wx.Yield()
		account.window = account_ui.account_frame( self, account.name, account )
		self.hide_me_timer.Start( 500, 1 )
		account.window.Raise()
		#event.StopPropagation()
		
	def OnColClick( self, event ):
		'''Handles requests to sort the accounts list'''
		self.clicked_column = event.GetColumn()
		self.sort_asc = not self.sort_asc
		self.list.SortItems( self.OnSort )

	def OnColRightClick( self, event ):
		pass

	def OnSort( self, item1, item2 ):
		'''The sorting function'''
		account1 = rex.accounts.accounts[ item1 ]
		account2 = rex.accounts.accounts[ item2 ]

		ac1 = ( account1.name,
				account1.connected,
				account1.server )
		ac2 = ( account2.name,
				account2.connected,
				account2.server )
		if self.sort_asc:
			val = cmp( ac1[self.clicked_column].lower(), ac2[self.clicked_column].lower() )
		else:
			val = cmp( ac2[self.clicked_column].lower(), ac1[self.clicked_column].lower() )
		return val

	def OnTimer( self, event ):
		'''Resets the status bar text back to "Ready"'''
		timer_id = event.GetId()
		if timer_id == ID_FRAME_TIMER:
			self.SetStatusText( "Ready" )
		elif timer_id == ID_HIDE_TIMER:
			self.Iconize()

	def disconnect_account( self, aid ):
		if aid is 0: return 1
		# Get the item by the AID
		index = self.list.FindItemData( -1, aid )
		item = self.list.GetItem( index )
		account = rex.accounts.accounts[ aid ]
		# Confirm
		self.list.SetStringItem( index, 0, account.name, self.disconnected_icon )
		self.list.SetStringItem( index, 1, "Ready" )
		self.resize_columns()
		wx.Yield()
		# call save to save the window dimensions before it dies
		account.save()
		account.connected = False
		# remove the reference to the service frame
		account.window = None
		self.Raise()
		return True

	def set_account_loading( self, aid, progress = "Loading..." ):
		if aid is 0: return 1
		# Get the item by the AID
		index = self.list.FindItemData( -1, aid )
		self.list.SetStringItem( index, 1, progress )
		self.SetStatusText( progress )
		self.resize_columns()
		wx.Yield()

	def set_account_loaded( self, aid ):
		if aid is 0: return 1
		# Get the item by the AID
		index = self.list.FindItemData( -1, aid )
		self.list.SetStringItem( index, 1, "Connected" )
		self.resize_columns()
		wx.Yield()
		self.SetStatusText( "Connected" )
		self.timer.Start( 5000, 1 )


class account_props( wx.Dialog ):
	'''Provides the UI to manipulate an accounts properties'''
	def __init__( self, parent, account ):
		type_selection = 0
		if account is None:
			caption = "New Account Properties"
			name, server, username, password = ( "", "", "", "" )
		else:
			caption = "Account Properties"
			name, server, username, password = (
					account.name,
					account.server,
					account.username,
					account.password )

		wx.Dialog.__init__( self, parent, -1, caption,
						   wx.DefaultPosition, wx.Size( 450, 250 )  )
		# Create the input fields
		self.name_control = wx.TextCtrl( self, -1, name )
		self.server_control  = wx.TextCtrl( self, -1, server )
		self.username_control  = wx.TextCtrl( self, -1, username )
		self.password_control  = wx.TextCtrl( self, -1, password, style=wx.TE_PASSWORD )

		self.grid = wx.FlexGridSizer( 5, 2, 2, 2 )
		inputs = [ ( wx.StaticText( self, -1, "Name", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.name_control, 1, wx.EXPAND | wx.GROW ),
				   ( wx.StaticText( self, -1, "Server",  style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.server_control, 1, wx.EXPAND  | wx.GROW ),
				   ( wx.StaticText( self, -1, "",  style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( wx.StaticText( self, -1, "",  style=wx.ALIGN_RIGHT ), 1, wx.EXPAND  | wx.GROW ), # this used to be the secure checkbox.  The location is reserved for future use.
				   ( wx.StaticText( self, -1, "Username", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.username_control, 1, wx.EXPAND | wx.GROW ),
				   ( wx.StaticText( self, -1, "Password", style=wx.ALIGN_RIGHT ), 0, wx.EXPAND ),
				   ( self.password_control, 1, wx.EXPAND | wx.GROW ) ]
		self.grid.AddMany( inputs )
		self.grid.AddGrowableCol( 1 )
		# Add the buttons
		self.button_sizer = wx.BoxSizer( wx.HORIZONTAL )
		btn = wx.Button( self, wx.ID_OK, "&Save" )
		btn.SetDefault()
		self.button_sizer.Add( (0,0) , 0, 1 )
		self.button_sizer.Add( btn, 1, 0 )
		self.button_sizer.Add( (10,10), 1, 1 )
		btn = wx.Button( self, wx.ID_CANCEL, "&Cancel" )
		self.button_sizer.Add( btn, 1, 0 )
		self.sizer = wx.BoxSizer( wx.VERTICAL )
		self.sizer.Add( self.grid, 1, wx.EXPAND | wx.NORTH | wx.SOUTH | wx.EAST | wx.WEST, 10 )
		self.sizer.Add( self.button_sizer, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.SOUTH, 20 )
		self.SetSizer( self.sizer )
		self.SetAutoLayout( 1 )
		icon = icon_manager.get_icon( "ESM" )
		self.SetIcon( icon )
		# Windows needs this call
		self.Layout()
	def OnSelectDir(self,event):
		dlg = wx.DirDialog(self, "Choose a local project directory:",
		                          style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
		res = dlg.ShowModal()
		if res  == wx.ID_OK:
			self.projectdir_control.SetValue(dlg.GetPath())
		dlg.Destroy()
